package com.orifine.dao.parser;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import com.orifine.utils.ClassUtils;

public class SqlOgnl {
	public static Object get(String expression, Map<String, Object> directory, Object... objs) {
		Object[] exps = expression.split("\\.");
		boolean isDollar = false;
		if (exps.length > 0 && ((String) exps[0]).charAt(0) == '$') {
			exps[0] = ((String) exps[0]).substring(1);
			isDollar = true;
		}
		for (int i = 0; i < exps.length; i++) {
			try {
				exps[i] = Integer.parseInt((String) exps[i]);
			} catch (NumberFormatException e) {
			}
		}

		if (isDollar) {
			if (exps[0] instanceof Integer) {
				try {
					return getObject(exps, 1, objs[(Integer) exps[0]]);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (SecurityException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (NoSuchMethodException e) {
				} catch (NoSuchElementException e) {
				}
			} else {
				try {
					return getObject(exps, 1, directory.get(exps[0]));
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (SecurityException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				} catch (NoSuchMethodException e) {
				} catch (NoSuchElementException e) {
				}
			}
		} else {
			return get(exps, objs);
		}
		return null;
	}

	public static Object get(Object[] exps, Object... objs) {
		for (Object obj : objs) {
			try {
				return getObject(exps, 0, obj);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (SecurityException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
			} catch (NoSuchElementException e) {
			}
		}
		return null;
	}

	public static Object get(String expression, Object... objs) {
		Object[] exps = expression.split("\\.");

		for (int i = 0; i < exps.length; i++) {
			try {
				exps[i] = Integer.parseInt((String) exps[i]);
			} catch (NumberFormatException e) {
			}
		}

		return get(exps, objs);
	}

	private static Object getObject(Object[] exps, int i, Object obj) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		for (; i < exps.length; i++) {
			if (obj != null) {
				obj = getObject(exps[i], obj);
			} else {
				break;
			}
		}

		return obj;
	}

	private static Object getObject(Object propertyName, Object obj) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		if (obj instanceof Map<?, ?>) {
			return ((Map<?, ?>) obj).get(propertyName);
		} else {
			if (propertyName instanceof Integer) {
				if (obj instanceof Object[]) {
					return ((Object[]) obj)[(Integer) propertyName];
				}

				if (obj instanceof List) {
					return ((List<?>) obj).get((Integer) propertyName);
				}

				throw new NoSuchElementException("非顺序集合不能使用数字查找");
			} else if (obj instanceof Collection) {
				ArrayList<Object> list = new ArrayList<Object>();
				for (Object o : (Collection<?>) obj) {
					Object returnObject = getObject(propertyName, o);
					if (returnObject != null) {
						Collection<Object> returnCollection = getCollection(returnObject);
						if (returnCollection != null) {
							list.addAll(returnCollection);
						} else {
							list.add(returnObject);
						}
					}
				}
				return list;
			} else {
				return obj.getClass().getMethod("get" + ClassUtils.getUpperName((String) propertyName)).invoke(obj);
			}
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static Collection<Object> getCollection(Object obj) {
		if (obj instanceof Object[]) {
			ArrayList arrayList = new ArrayList();
			for (int i = 0; i < Array.getLength(obj); i++) {
				arrayList.add(Array.get(obj, i));
			}
			return arrayList;
		} else {
			if (obj instanceof Collection) {
				return (Collection) obj;
			}
		}
		return null;
	}
}
